/*++****************************************************************************
*
*	Name: lib_usb_cdc.c
*
*	Description: This library is a wrapper for the USB Communication Device Class. 
*				 The USB stack is provided by Microchip. 
*
*	Supported Comilers:
*		MPLAB C18
*		MPLAB C32
*
*	Revision History:
*	Date	Who	Comments	
*	------	---	---------------------------------------------------------------
*	110521	DHT	Created
*	110808	RLP	Return size written in lib_usb_cdc_write_blocked()
****************************************************************************--*/
#include <stdio.h>
#include <stdarg.h>
#include "USB/usb.h"
#include "USB/usb_function_cdc.h"
#include "lib_usb_cdc.h"


// character buffer for the usb_printf function. The reason why it is 
// a global and not inside the usb_printf function is because it needs
// to be persistent and not temporary. The USB stack does not copy the 
// buffer into another buffer before sending. It uses the same buffer 
// to send out therefore temporary variables will be out of scope.
static char buf[255]; 

/*********************************************************************
 * Function:        INT16 lib_usb_cdc_open()
 *
 * Overview:		Init USB module for USB CDC device
 *
 * PreCondition:    None
 *
 * Input:			None
 *
 * Output:          success = 0
 *					error codes can be found in lib_usb_cdc.h
 *
 * Note:            This function blocks and waits for the usb to 
 *					finish configuring before returning. This can 
 *					take up to several seconds.
 ********************************************************************/
INT16 lib_usb_cdc_open()
{
	USBDeviceInit();				//usb_device.c.  Initializes USB module SFRs and firmware
    								//variables to known states.
    								
	#if defined(USB_INTERRUPT)
	USBDeviceAttach();
	#endif 
	
	// wait for usb to configure successfully
	while(USBDeviceState != CONFIGURED_STATE)
	{
		#ifdef USB_POLLING
		USBDeviceTasks();		// service usb interrupt
		#endif
	}	

	return LIB_USB_CDC_SUCCESS;
}


/*********************************************************************
 * Function:        INT16 lib_usb_cdc_close()
 *
 * Overview:		Detach USB device from host
 *
 * PreCondition:    None
 *
 * Input:			None
 *
 * Output:          success = 0
 *					error codes can be found in lib_usb_cdc.h
 *
 * Note:            Not yet tested!!!
 ********************************************************************/
INT16 lib_usb_cdc_close()
{
	USBSoftDetach();
	return LIB_USB_CDC_SUCCESS;
}


/*********************************************************************
 * Function:        INT16 lib_usb_cdc_read(UINT8 *buffer, UINT8 size)
 *
 * Overview:		Read from USB port
 *
 * PreCondition:    lib_usb_cdc_open()
 *
 * Input:			buffer - byte array to store bytes read
 *					size - size of buffer variable
 *
 * Output:          Number of bytes read
 *
 * Note:            A maximum of 64 bytes can be read each time
 ********************************************************************/
INT16 lib_usb_cdc_read(UINT8 *buffer, UINT8 size)
{
	return getsUSBUSART((void*)buffer, size);		
}
	

/*********************************************************************
 * Function:        INT16 lib_usb_cdc_write(UINT8 *buffer, UINT8 size)
 *
 * Overview:		Write bytes to the USB port
 *
 * PreCondition:    lib_usb_cdc_open()
 *
 * Input:			buffer - array of bytes to write
 *					size - size of buffer variable
 *
 * Output:          Number of bytes written
 *
 * Note:            A maximum of 255 bytes can be written at a time
 ********************************************************************/
INT16 lib_usb_cdc_write(UINT8 *buffer, UINT8 size)
{
	// check to see if usb is ready to send
	if(mUSBUSARTIsTxTrfReady())
    {
	    // Queue bytes. Does not really send right away.
    	// Bytes will be sent in CDCTxService routine
    	putUSBUSART((void*)buffer, size);	
    	return size;
    }
    
    return 0; // usb not ready to send more bytes
}


/*********************************************************************
 * Function:        INT16 lib_usb_cdc_write_blocked(UINT8 *buffer, UINT8 size)
 *
 * Overview:		Write bytes to the USB port and block until all bytes
 *					are sent.
 *
 * PreCondition:    lib_usb_cdc_open()
 *
 * Input:			buffer - array of bytes to write
 *					size - size of buffer variable
 *
 * Output:          Number of bytes written
 *
 * Note:            A maximum of 255 bytes can be written at a time.
 *					This is a blocked io. 
 ********************************************************************/
INT16 lib_usb_cdc_write_blocked(UINT8 *buffer, UINT8 size)
{
	INT16 rc = lib_usb_cdc_write(buffer, size);
	
	if (rc > 0)
	{
		// wait until all data is sent
	    while (!mUSBUSARTIsTxTrfReady())
	    	CDCTxService();		// service cdc transmit
	}
	return(size);	
}
	

/*********************************************************************
 * Function:        INT16 lib_usb_cdc_printf(const ROM char *fmt, ...)
 *
 * Overview:		Output string to usb with printf 
 *
 * PreCondition:    lib_usb_cdc_open()
 *
 * Input:			fmt - format of string
 *					... - variable list of variables
 *
 * Output:          Number of bytes written
 *
 * Note:            A maximum of 255 bytes can be written at a time
 ********************************************************************/
INT16 lib_usb_cdc_printf(const ROM char *fmt, ...)
{
	if(mUSBUSARTIsTxTrfReady())
    {	  
		int n;
	    va_list ap;
	    va_start (ap, fmt);
	    n = vsprintf (buf, fmt, ap);
	    va_end (ap);	    

		if (n > 0)	    	    
	    	putsUSBUSART(buf);
	    	
	    return n;
	} 
	
	return 0;
}	


/*********************************************************************
 * Function:        INT16 lib_usb_cdc_printf_blocked(const ROM char *fmt, ...)
 *
 * Overview:		Output string to usb with printf and wait until message
 *					successfully sends.
 *
 * PreCondition:    lib_usb_cdc_open()
 *
 * Input:			fmt - format of string
 *					... - variable list of variables
 *
 * Output:          Number of bytes written
 *
 * Note:            A maximum of 255 bytes can be written at a time.
 *					This is a blocked io. Use the regular lib_usb_cdc_printf
 *					if you want non-blocking io.
 ********************************************************************/
INT16 lib_usb_cdc_printf_blocked(const ROM char *fmt, ...)
{
	if(mUSBUSARTIsTxTrfReady())
    {	  
		int n;
	    va_list ap;
	    va_start (ap, fmt);
	    n = vsprintf (buf, fmt, ap);
	    va_end (ap);	    

		if (n > 0)	    	  
		{			  
	    	putsUSBUSART(buf);
	    	
	    	// wait until all data is sent
	    	while (!mUSBUSARTIsTxTrfReady())
	    		CDCTxService();		// service cdc transmit
	 	}
	    	
	    return n;
	} 
	
	return 0;
}	


/*********************************************************************
 * Function:        INT16 lib_usb_cdc_process_main()
 *
 * Overview:		Service USB Stack
 *
 * PreCondition:    lib_usb_cdc_open()
 *
 * Input:			None
 *
 * Output:          None
 *
 * Note:            Must call this function in your main loop
 ********************************************************************/
void lib_usb_cdc_process_main()
{
	#if defined(USB_POLLING)
	// Check bus status and service USB interrupts.
    USBDeviceTasks(); // Interrupt or polling method.  If using polling, must call
        				  // this function periodically.  This function will take care
        				  // of processing and responding to SETUP transactions 
        				  // (such as during the enumeration process when you first
        				  // plug in).  USB hosts require that USB devices should accept
        				  // and process SETUP packets in a timely fashion.  Therefore,
        				  // when using polling, this function should be called 
        				  // regularly (such as once every 1.8ms or faster** [see 
        				  // inline code comments in usb_device.c for explanation when
        				  // "or faster" applies])  In most cases, the USBDeviceTasks() 
        				  // function does not take very long to execute (ex: <100 
        				  // instruction cycles) before it returns.
    #endif
    
    CDCTxService();		// service cdc transmit
}



#if defined(__18CXX) && defined(USB_INTERRUPT)

/*********************************************************************
 * Function:        void lib_usb_cdc_process_interrupt()
 *
 * Overview:		Services USB interrupt 
 *
 * PreCondition:    None
 *
 * Input:			None
 *
 * Output:          None
 *
 * Note:            Only need to call this in C18 code. Not needed
 *					for C32 code.
 ********************************************************************/
void lib_usb_cdc_process_interrupt()
{
	USBDeviceTasks();		// service usb interrupt
}

#endif // #if defined(__18CXX) && defined(USB_INTERRUPT)


